package com.cml.domain.service;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.cml.common.config.Configuration;
import com.cml.common.dto.entity.ServiceInstance;
import com.cml.common.dto.message.ServiceInstanceChangeRequest;
import com.cml.domain.entity.Session;
import org.apache.log4j.Logger;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 姓名：陈茂林
 * 时间：2023/11/7 8:59
 * 描述：
 */
public class ServiceInstanceManagerService {
    Logger logger = Logger.getLogger(ServiceInstanceManagerService.class);
    private ConcurrentHashMap<String, List> serviceRegisterList = new ConcurrentHashMap<>();

    private ConcurrentHashMap<String, List> serviceSubscribeList = new ConcurrentHashMap<>();
    public ServiceInstanceManagerService(){
        new HearbeatThread().start();
        new SubscribeSessionThread().start();
    }

    public void subscribe(Session session, String serviceName){
        List subscribeSessionList = serviceSubscribeList.get(serviceName);
        if(subscribeSessionList == null){
            synchronized (this){
                subscribeSessionList= new ArrayList();
                serviceSubscribeList.put(serviceName,subscribeSessionList);
            }
        }
        //session是close状态，需要销毁
        subscribeSessionList.add(session);
        synServiceInstance(session,serviceName);
    }


    private void serviceInstanceChange(String serviceName){
        List<Session> subscribeSessionList =this.serviceSubscribeList.get(serviceName);
        if(subscribeSessionList != null){
            for(Session session: subscribeSessionList){
                    synServiceInstance(session,serviceName);

            }
        }
    }

    private void synServiceInstance(Session session,String serviceName) {
        List serviceRegisterOnlineList =this.serviceRegisterList.get(serviceName);
        if(serviceRegisterOnlineList != null){
            ServiceInstanceChangeRequest serviceInstanceChangeRequest = new ServiceInstanceChangeRequest();
            serviceInstanceChangeRequest.setServiceInstanceRegisterList(JSONObject.toJSONString(serviceRegisterOnlineList));
            try {
                session.sendMessage(serviceInstanceChangeRequest);
            } catch (InterruptedException e) {
                logger.error(e);
            }
        }
    }

    public boolean registerServiceInstance(ServiceInstance serviceInstance){
        List serviceRegisterOnlineList = this.serviceRegisterList.get(serviceInstance.getServiceName());
        synchronized (this){
            if(serviceRegisterOnlineList == null){
                serviceRegisterOnlineList=new ArrayList();
                this.serviceRegisterList.put(serviceInstance.getServiceName(),serviceRegisterOnlineList);
            }
            serviceRegisterOnlineList.add(serviceInstance);
            logger.info("服务注册提醒：" + serviceInstance);
        }
        serviceInstanceChange(serviceInstance.getServiceName());
        return true;
    }

    public void hearbeat(ServiceInstance serviceInstance){
        List serviceRegisterOnlineList = this.serviceRegisterList.get(serviceInstance.getServiceName());
        if(serviceRegisterOnlineList.size() == 0){
            this.registerServiceInstance(serviceInstance);
        }
        for (int i = 0; i < serviceRegisterOnlineList.size(); i++) {
            ServiceInstance onlineServiceInstance = (ServiceInstance) serviceRegisterOnlineList.get(i);
            if(onlineServiceInstance.toString().equals(serviceInstance.toString())){
                onlineServiceInstance.setLastHearbeatTime(new Date());
            }
        }
    }



    class HearbeatThread extends Thread{
        @Override
        public void run() {
            int heartbeatIntervalTime = Configuration.getInstance().getServiceHeartbeatIntervalTime();
            while (true){
                try {
                    Date mathHeartbeatTime= DateUtil.offset(new Date(), DateField.MILLISECOND,0-heartbeatIntervalTime);
                    logger.debug("心跳检查时间为:" +mathHeartbeatTime);
                    Enumeration<String> serviceInstanceNameList =  serviceRegisterList.keys();
                    while(serviceInstanceNameList.hasMoreElements()){
                        String serviceInstanceName = serviceInstanceNameList.nextElement();
                        List<ServiceInstance> serviceInstanceList =serviceRegisterList.get(serviceInstanceName);
                        List<ServiceInstance> checkServiceInstanceList =new ArrayList<>();
                        checkServiceInstanceList.addAll(serviceInstanceList);
                        boolean serviceInstanceIsChange=false;
                        for(ServiceInstance serviceInstance : serviceInstanceList){
                            if (serviceInstance.getLastHearbeatTime().compareTo(mathHeartbeatTime) < 0){
                                checkServiceInstanceList.remove(serviceInstance);
                                logger.info("移出服务实例："+serviceInstance);
                                serviceInstanceIsChange=true;
                            }
                        }
                        serviceRegisterList.put(serviceInstanceName,checkServiceInstanceList);
                        if(serviceInstanceIsChange){
                            serviceInstanceChange(serviceInstanceName);
                        }
                    }
                    Thread.sleep(heartbeatIntervalTime);
                } catch (InterruptedException e) {
                    logger.error(e.getMessage());
                }
            }
        }
    }

    class SubscribeSessionThread extends Thread{
        int subscribeSessionCheckIntervalTime =1000;
        @Override
        public void run() {
            while (true){
                Enumeration<String> serviceInstanceNameList =  serviceSubscribeList.keys();
                while(serviceInstanceNameList.hasMoreElements()) {
                    String serviceInstanceName = serviceInstanceNameList.nextElement();
                    List<Session>  serviceSubscribeSessionList=serviceSubscribeList.get(serviceInstanceName);
                    List openSessionList = new ArrayList();
                    for(Session session:serviceSubscribeSessionList){
                        if(session.isClose()){
                            logger.info("服务："+serviceInstanceName+" session:"+session.getSessionId()+"移出！");
                        }else{
                            openSessionList.add(session);
                        }
                    }
                    serviceSubscribeList.put(serviceInstanceName,openSessionList);
                }
                try {
                    Thread.sleep(subscribeSessionCheckIntervalTime);
                } catch (InterruptedException e) {
                    logger.error(e);
                }
            }
        }
    }
}
